package com.panopset.sf;

import java.awt.Component;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import java.net.URI;
import java.util.Date;
import java.util.List;

import javax.swing.JDialog;
import javax.swing.JFrame;

import com.panopset.Numbers;
import com.panopset.Util;
import java.util.ArrayList;

/**
 * Usually used for about boxes, a PopupBox is a modeless dialog that disappears
 * when the user does a mouse click or presses any key.
 *
 * @author Karl Dinwiddie
 */
public abstract class PopupBox {

    /**
     * @return PopupBox size.
     */
    public abstract Dimension createSize();

    /**
     * @return PopupBox display component.
     */
    public abstract Component createComponent();

    /**
     * Size.
     */
    private Dimension sz;

    /**
     *
     * @return Size.
     */
    private Dimension getSize() {
        if (sz == null) {
            sz = createSize();
        }
        return sz;
    }

    /**
     * Parent frame.
     */
    private JFrame parent;

    /**
     * Set a parent frame for positioning.
     * @param frame Parent frame.
     */
    public final void setParent(final JFrame frame) {
        this.parent = frame;
    }

    /**
     * Internal component.
     */
    private Component component;

    /**
     *
     * @return Internal component.
     */
    private Component getComponent() {
        if (component == null) {
            component = createComponent();
        }
        return component;
    }

    /**
     * Links.
     */
    private final List<Link> links = new ArrayList<Link>();

    /**
     * Add a link to the display area.
     *
     * @param area
     *            Area where link will be hot.
     * @param urlString
     *            URL as String.
     */
    public final void addLink(final Rectangle area, final String urlString) {
        links.add(new Link(area, urlString));
    }

    /**
     * Dispose popup box.
     */
    public final void dispose() {
        if (dialog != null) {
            dialog.dispose();
            dialog = null;
        }
    }

    /**
     * Show popup box.
     */
    public final void show() {
        getDialog().setVisible(true);
    }

    /**
     * Popup box dialog.
     */
    private JDialog dialog;

    /**
     * @return Popup box dialog.
     */
    private JDialog getDialog() {
        if (dialog == null) {
            dialog = new JDialog();
            dialog.setUndecorated(true);
            dialog.setSize(getSize());
            if (parent != null) {
                dialog.setLocation(Util.centerInRect(dialog.getSize(),
                        parent.getBounds()));
            }
            dialog.add(getComponent());
            dialog.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
            getComponent().addKeyListener(new KeyAdapter() {

                @Override
                public void keyPressed(final KeyEvent e) {
                    PopupBox.this.dispose();
                }

            });
            getComponent().addMouseListener(new MouseAdapter() {

                /**
                 * Last click time.
                 */
                private long lastClickTime = 0;

                @Override
                public void mousePressed(final MouseEvent e) {
                    for (Link link : links) {
                        if (Util.pointInRect(e.getPoint(), link.getArea())) {
                            return;
                        }
                    }
                    PopupBox.this.dispose();
                }

                @Override
                public void mouseClicked(final MouseEvent e) {
                    for (Link link : links) {
                        if (Util.pointInRect(e.getPoint(), link.getArea())) {
                            try {
                                synchronized (this) {
                                    long time = new Date().getTime();
                                    if (time - lastClickTime

                                    > Numbers.Integers.QUARTER_SECOND
                                            .getValue()) {
                                        Desktop.getDesktop().browse(
                                                new URI(link.getUrl()));
                                    }
                                    lastClickTime = time;
                                }
                                return;
                            } catch (Exception e1) {
                                Util.log(e1);
                            }
                        }
                    }
                    PopupBox.this.dispose();
                }

            });
            getComponent().addMouseMotionListener(new MouseMotionAdapter() {

                @Override
                public void mouseMoved(final MouseEvent e) {
                    for (Link link : links) {
                        if (Util.pointInRect(e.getPoint(), link.getArea())) {
                            getComponent().setCursor(

                            Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
                            return;
                        }
                    }
                    getComponent().setCursor(
                            Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
                }

            });
        }
        return dialog;
    }
}
